package com.ourteam.system.api;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAccount;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import com.ourteam.frame.web.ApplicationModel;
import com.ourteam.system.domain.SystemAction;
import com.ourteam.system.domain.SystemModule;
import com.ourteam.system.domain.SystemRole;
import com.ourteam.system.domain.SystemUser;
import com.ourteam.system.domain.SystemUserPassword;
import com.ourteam.system.service.ISysRoleService;
import com.ourteam.system.service.ISysUserService;
import com.ourteam.system.service.SysRoleServiceFactory;
import com.ourteam.system.service.SysUserServiceFactory;

public class UserAuthorizingRealm extends AuthorizingRealm {
	/**
	 * Logger for this class
	 */
	private static final Log logger = LogFactory.getLog(UserAuthorizingRealm.class);

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

		ISysRoleService sysRoleService = SysRoleServiceFactory.getSysRoleService();

		ApplicationModel applicationModel = (ApplicationModel) principalCollection.getPrimaryPrincipal();

		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

		try {
			SystemRole[] systemRoles = sysRoleService.getSysUserRoles(applicationModel.getUserId());

			long[] roleIds = new long[systemRoles.length];

			for (int i = 0; i < roleIds.length; i++) {
				roleIds[i] = systemRoles[i].getId();
			}

			SystemModule[] systemModules = sysRoleService.getSysRoleModules(roleIds);

			for (int i = 0; i < systemModules.length; i++) {
				SystemModule systemModule = systemModules[i];
				authorizationInfo.addStringPermission("module:" + systemModule.getId());
			}

			SystemAction[] systemActions = sysRoleService.getSysRoleActions(roleIds);

			for (int i = 0; i < systemActions.length; i++) {
				SystemAction systemAction = systemActions[i];
				authorizationInfo
						.addStringPermission("module:" + systemAction.getModuleId() + "action:" + systemAction.getId());
			}

		} catch (Exception e) {
			logger.error("doGetAuthorizationInfo error!", e);
		}

		return authorizationInfo;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
			throws AuthenticationException {

		ISysUserService sysUserService = SysUserServiceFactory.getSysUserService();

		UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;

		if (usernamePasswordToken.getUsername() == null) {
			throw new AccountException("Null usernames are not allowed by this realm.");
		}

		try {
			SystemUser systemUser = sysUserService.getSysUserByAccount(usernamePasswordToken.getUsername());

			if (systemUser == null) {
				throw new UnknownAccountException(
						"No account found for user [" + usernamePasswordToken.getUsername() + "]");
			}

			if (systemUser != null) {

				if (systemUser.getStatus().equals("LOCKED")) {
					throw new UnknownAccountException("account is locked");
				}

				SystemUserPassword userPassword = sysUserService
						.getSysUserPassword(usernamePasswordToken.getUsername());

				if (userPassword == null) {
					throw new UnknownAccountException(
							"No account found for user [" + usernamePasswordToken.getUsername() + "]");
				}

				SimpleAccount authenticationInfo = new SimpleAccount(getAppModel(systemUser),
						userPassword.getPassword(), getName());

				return authenticationInfo;

			}

		} catch (Exception e) {
			throw new AuthenticationException(e);
		}
		return null;
	}

	protected ApplicationModel getAppModel(SystemUser systemUser) {

		ApplicationModel applicationModel = new ApplicationModel();

		applicationModel.setUserName(systemUser.getName());

		applicationModel.setUserId(systemUser.getId());

		applicationModel.setUserAccount(systemUser.getAccount());

		applicationModel.setUserPhoto(systemUser.getPhotoPath());

		applicationModel.setLoginTime(new Date());

		ISysRoleService sysRoleService = SysRoleServiceFactory.getSysRoleService();

		try {
			SystemRole[] systemRoles = sysRoleService.getSysUserRoles(applicationModel.getUserId());

			List<String> roleNames = new ArrayList<String>();

			List<Long> roleIds = new ArrayList<>();

			for (int i = 0; i < systemRoles.length; i++) {
				SystemRole systemRole = systemRoles[i];
				if (roleNames.contains(systemRole.getName()) == false) {
					roleNames.add(systemRole.getName());
				}

				if (roleIds.contains(systemRole.getId()) == false) {
					roleIds.add(systemRole.getId());
				}
			}

			applicationModel.setUserRoleNames(roleNames.toArray(new String[roleNames.size()]));

			applicationModel.setUserRoleIds(ArrayUtils.toPrimitive(roleIds.toArray(new Long[roleIds.size()])));

		} catch (Exception e) {
			e.printStackTrace();
		}

		return applicationModel;

	}
}
